﻿using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Guids;
using Volo.Abp;
using my.abp.Application.Contracts.Dtos;
using my.abp.Domain.Shared.Entities;
using my.abp.Domain.IManagers;
using my.abp.Domain.Authorization;
using Lazy.Captcha.Core;
using System.ComponentModel;
using Yitter.IdGenerator;
using Framework.Core.Options;
using Microsoft.IdentityModel.Tokens;
using my.abp.Domain.Shared.Etos;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Security.Claims;
using Microsoft.AspNetCore.Http;
using Volo.Abp.EventBus.RabbitMq;
using Microsoft.Extensions.Options;
using my.abp.Domain.Managers;
using my.abp.Domain.Shared.Enums;
using Framework.Core.Helper;
using my.abp.Application.Contracts.Dtos.Account;
using Framework.Core.ServiceResult;
using Framework.Core.Consts;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Users;
using Framework.AspNetCore.User;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Authentication;
using my.abp.Application.Contracts.IServices.Auth;
using my.abp.Domain.IManagers.User;
using Framework.Core.Enums;
using Framework.SqlSugarCore.Repositories;
using my.abp.Domain.Managers.User;
using my.abp.Domain.IManagers.Org;
using my.abp.Domain.Managers.Org;
using my.abp.Domain.IManagers.Menu;
using Framework.AspNetCore.UnifyResult;
using Volo.Abp.Caching;
using Framework.Caching.FreeRedis;

namespace my.abp.Application.Services.Auth
{
    public class SysAuthService : ApplicationService, ISysAuthService
	{
		private readonly ICaptcha _captcha;
		private IHttpContextAccessor _httpContextAccessor;
		private readonly IDistributedEventBus _distributedEventBus;
		private IAccountManager _accountManager;
		private ISysUserManager _sysUserManager;
		private ISysOrgManager _sysOrgManager;
		private ISysMenuManager _sysMenuManager;
		private readonly IWantDistributedCache _sysCache;
		public SysAuthService(
			
			IHttpContextAccessor httpContextAccessor,
			ICaptcha captcha, 
			RabbitMqDistributedEventBus distributedEventBus,
			ISysUserManager sysUserManager,
			IAccountManager accountManager,
			ISysOrgManager sysOrgManager,
			ISysMenuManager sysMenuManager, 
			IWantDistributedCache sysCache)
		{
			_httpContextAccessor = httpContextAccessor;
			_distributedEventBus = distributedEventBus;
			_captcha = captcha;
			_sysUserManager = sysUserManager;
			_accountManager = accountManager;
			_sysOrgManager = sysOrgManager;
			_sysMenuManager = sysMenuManager;
			_sysCache = sysCache;
		}

		/// <summary>
		/// 登录
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		[AllowAnonymous]
		//[Permission("test")]
		public async Task<LoginOutputDto> PostLoginAsync(LoginInputVo input)
		{
			// 判断验证码
			//if (!_captcha.Validate(input.Id, input.Code.ToUpper()))
			//	throw new UserFriendlyException("验证码错误！");

			// 获取账号
			SysUser user = await _sysUserManager.GetAsync(input.UserName);
			if (user == null) throw new UserFriendlyException("账号不存在！");    // 判断账号是否存在

			// 账号是否被冻结
			if (user.Status == StatusEnum.Disable)
				throw new UserFriendlyException("账号已冻结！");

			if (user.Password != MD5Encryption.Encrypt(input.Password, true, false))
				throw new UserFriendlyException("密码不正确！");

			//获取token
			var accessToken = await _accountManager.GetToken(user);
			var refreshToken = await _accountManager.GetRefreshToken(user);
			
			// 这里抛出一个登录的事件
			if (_httpContextAccessor.HttpContext is not null)
			{
				LoginEventArgs loginEto = new LoginEventArgs();
				loginEto.UserName = user.Name;
				loginEto.UserId = user.Id;
				await _distributedEventBus.PublishAsync(loginEto);
			}

			// 删除用户拥有按钮权限集合缓存
			_sysCache.Remove<List<string>, string>(CacheConst.KeyUserButton + user.Id, CacheConst.cacheName);

			// 删除用户所属机构缓存
			_sysCache.Remove<List<long>, string>($"{CacheConst.KeyUserOrg}{user.Id}",CacheConst.cacheName);

			// 删除用户最大角色数据范围缓存
			_sysCache.Remove<dynamic, string>($"{CacheConst.KeyRoleMaxDataScope}{user.Id}",CacheConst.cacheName);

			return new LoginOutputDto { Token = accessToken, RefreshToken = refreshToken };
		}

		/// <summary>
		/// 登录
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		[AllowAnonymous]
		//[Permission("test")]
		[NonUnify]
		public async Task<LoginOutputDto> LoginUser()
		{
			//// 判断验证码
			//if (!_captcha.Validate(input.Id, input.Code.ToUpper()))
			//	throw new UserFriendlyException("验证码错误！");

			// 获取账号
			SysUser user = await _sysUserManager.GetAsync("superadmin");
			if (user == null) throw new UserFriendlyException("账号不存在！");    // 判断账号是否存在

			// 账号是否被冻结
			if (user.Status == StatusEnum.Disable)
				throw new UserFriendlyException("账号已冻结！");

			if (user.Password != MD5Encryption.Encrypt("111111", true, false))
				throw new UserFriendlyException("密码不正确！");

			//获取token
			var accessToken = await _accountManager.GetToken(user);
			var refreshToken = await _accountManager.GetRefreshToken(user);
			//return new { Token = accessToken, RefreshToken = refreshToken };

			// 删除用户拥有按钮权限集合缓存
			_sysCache.Remove<List<string>, string>(CacheConst.KeyUserButton + user.Id, CacheConst.cacheName);

			// 删除用户所属机构缓存
			_sysCache.Remove<List<long>, string>($"{CacheConst.KeyUserOrg}{user.Id}", CacheConst.cacheName);

			// 删除用户最大角色数据范围缓存
			_sysCache.Remove<dynamic, string>($"{CacheConst.KeyRoleMaxDataScope}{user.Id}", CacheConst.cacheName);

			return new LoginOutputDto { Token = accessToken, RefreshToken = refreshToken };
		}

		/// <summary>
		/// 获取验证码
		/// </summary>
		/// <returns></returns>
		[AllowAnonymous]
		[DisplayName("获取验证码")]
		public CaptchaImageDto GetCaptcha()
		{
			var codeId = YitIdHelper.NextId().ToString();
			var captcha = _captcha.Generate(codeId);

			return new CaptchaImageDto { Id = codeId, Img = captcha.Base64 };
		}

		protected new Framework.AspNetCore.User.CurrentUser CurrentUser => (Framework.AspNetCore.User.CurrentUser)LazyServiceProvider.LazyGetRequiredService(typeof(Framework.AspNetCore.User.CurrentUser)); 
		
		/// <summary>
		/// 刷新token
		/// </summary>
		/// <param name="refresh_token"></param>
		/// <returns></returns>
		public async Task<LoginOutputDto> PostRefreshAsync([FromQuery] string refresh_token)
		{
			if (CurrentUser.Id is null)
			{
				throw new UserFriendlyException("用户未登录");
			}

			var authResult = await _httpContextAccessor.HttpContext.AuthenticateAsync(TokenTypeConst.Refresh);

			if (authResult.Succeeded)
			{
				if(authResult.Properties.ExpiresUtc < DateTime.UtcNow)
				{
					throw new UserFriendlyException("用户未登录");
				}

				var Account = CurrentUser.Account;

				SysUser user = await _sysUserManager.GetAsync(Account);

				//获取token
				var accessToken = await _accountManager.GetToken(user);
				var refreshToken = await _accountManager.GetRefreshToken(user);
				//return new { Token = accessToken, RefreshToken = refreshToken };

				return new LoginOutputDto { Token = accessToken, RefreshToken = refreshToken };
			}

			throw new UserFriendlyException("用户未登录");
		}

		/// <summary>
		/// 获取登录账号
		/// </summary>
		/// <returns></returns>
		[Authorize]
		[DisplayName("获取登录账号")]
		public async Task<LoginUserOutput> GetUserInfo()
		{
			_sysUserManager.GetBaseInfo();

			var user = await _sysUserManager.GetBaseInfo();
			// 获取机构
			var org = await _sysOrgManager.GetOrg();
			// 获取拥有按钮权限集合
			var buttons = await _sysMenuManager.GetOwnBtnPermList();

			return new LoginUserOutput
			{
				Id = user.Id,
				Account = user.Account,
				Name = user.Name,
				OrgId = user.OrgId,
				OrgName = org?.Name,
				Buttons = buttons
			};
		}
	}
}
